﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace II2svn
{
    public partial class Form1 : Form
    {
        bool shift_down;

        public int Z { set; get; }
        public int n { set; get; }
        public int Q { set; get; }

        public double sgm { set; get; }
        public double alpha { set; get; }

        double[,] L;

        public class vec: List<int>
        {
            public int q;
            public double tmp;

            public override string  ToString()
            {
               string str = q.ToString()+"\t";
                foreach (var o in this)
	            {
		            str+=o.ToString()+" ";
	            }

                return str;                
            }

            public vec()
            {
                q = 0;
            }

            public vec(List<int> _body,int _q=0)
            {
                AddRange(_body);
                q = _q;
            }

            public vec(string str){
                var spl = str.Split('\t');
                q = Int32.Parse(spl[0]);

                var lines = spl[1].Trim().Split(' ');

                this.Clear();
                foreach(var line in lines){
                    this.Add(Int32.Parse(line));
                }
            }
        }

        List<vec> X;
        

        enum MESSTYPE { EUCLIDE, TOH };
        enum KTYPE { EXP, SQ, SIN };

        delegate double messFunc(vec a, vec b);
        delegate double KFunc(vec a, vec b);

        List<messFunc> messList;
        List<KFunc> KList;

        Random rand;
        

        void Init()
        {
           // Z = 2;
           // Q = 3;
           // n = 6 * 6;
           // L = new double[Z, Q];

            rand = new Random();

            alpha = 1.0;
            sgm = .001;

            X = new List<vec>();

            //listBoxX.DataBindings.Add("Items", this, "X");
            listBoxX.DataSource = X;
            listBoxX.FormattingEnabled = false;

            messList = new List<messFunc>();
            KList = new List<KFunc>();

            //Евклид
            //Хэмминг
            //косинус
            //Танимото
            //Махаланобис
            messList.Add(mEuclide);
            comboMess.Items.Add("Евклид");

            messList.Add(mHamming);
            comboMess.Items.Add("Хэмминг");

            messList.Add(mCos);
            comboMess.Items.Add("косинус");

            messList.Add(mTanimoto);
            comboMess.Items.Add("Танимото");

            messList.Add(mMaha);
            comboMess.Items.Add("Махаланобис");

            comboMess.SelectedIndex = 0;

            //Экспонента
            //Квадрат
            //Синус

            KList.Add(kExp);
            comboK.Items.Add("Экспонента");


            KList.Add(kSqr);
            comboK.Items.Add("Квадрат");


            KList.Add(kSin);
            comboK.Items.Add("Синус");

            comboK.SelectedIndex = 0;

            sft = 0;
            // AddTB("Z");
            // AddTB("n");
            // AddTB("Q");
            AddTB("sgm");
            AddTB("alpha");
        }

        int sft;
        
        void AddTB(string text)
        {
            int ysft = 25;
            TextBox tb = new TextBox();
            Label lb = new Label();

            panel2.Controls.Add(tb);
            panel2.Controls.Add(lb);

            Point pos = new Point(10, 10);
            pos.Offset(10, sft);

            lb.Text = text;
            lb.Location = pos;

            pos.Offset(100, 0);
            tb.Location = pos;
            tb.Size = new System.Drawing.Size(100, ysft - 1);

            tb.DataBindings.Add("Text", this, text);

            sft += ysft;
        }

        public Form1()
        {
            InitializeComponent();
        }



        messFunc mess;
        KFunc K;

        double mHamming(vec a, vec b)
        {
            double sum = 0;
            for (int i = 0; i < a.Count; i++)
            {
                sum += a[i] != b[i] ? 1 : 0;
            }
            return sum;
        }

        double mEuclide(vec a,vec b){
            double sum = 0;
            for (int i = 0; i < a.Count; i++)
            {
                sum += (a[i]-b[i])*(a[i]-b[i]);
            }

            return Math.Sqrt(sum);
        }

        double uMult(vec a, vec b)
        {
            double sum = 0;
            for (int i = 0; i < a.Count; i++)
            {
                sum += a[i]*b[i];
            }
            return sum;
        }

        double uMeg(vec a, vec b)
        {
            double sum = 0;
            for (int i = 0; i < a.Count; i++)
            {
                sum += a[i] * a[i];
            }

            return Math.Sqrt(sum);
        }

        double mCos(vec a, vec b)
        {  
            return uMult(a,b)/(uMeg(a,b)*uMeg(a,b));
        }

        double mTanimoto(vec a, vec b)
        {
            //mes(x,x1) =(x,x1)/((x,x)+(x1, x1)-(x, x1))
            return uMult(a,b)/( uMult(a,a) + uMult(b,b) - uMult(a,b) );
        }

        double mMaha(vec a, vec b)
        {
            return 0;
        }

        double kExp(vec a, vec b)
        {
            return Math.Exp(-alpha * mess(a, b) * mess(a, b));
        }

        double kSqr(vec a, vec b)
        {
            return 1.0 / (1 + alpha * mess(a, b) * mess(a, b));
        }

        double kSin(vec a, vec b)
        {
            var tmp = alpha * mess(a, b) * mess(a, b);
            return Math.Abs(Math.Sin(tmp) / tmp);
        }

        double Kq(vec x, int q)
        {
            double sum =0;
            for (int z = 0; z < Z; z++)
            {
                sum += L[z, q] * K(x, X[z]);
            }

            return sum;
        }

        void Train()
        {
            var flag=true;
            while(flag)
            {
              flag=false;
              for (int i=0; i<Z;i++) // цикл по всем элементам 
                { 

                  int p = X[i].q;
                  int m = GuessQ(X[i]);

                  if(m!=p){
                      double cht = Math.Abs((L[i, p] - L[i, m]) * .25);//ускорим чуток
                      L[i,p]+=cht+sgm;
                      L[i,m]-=cht+sgm;
                      flag=true;
                  }                   
                }
            }

        }
               

        int GuessQ(vec a, bool showQ = false)
        {
            int m = 0;
            double mv = 0;
            for (int q = 0; q < Q; q++)
            {
                var kq = Kq(a, q);
                if (showQ) listQchar.Items[q] = kq;
                if (kq > mv) { mv = kq; m = q; }
            }

            return m;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            bitMap1.Init(6);
            Init();
        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.ShiftKey)
            {
                shift_down = true;
                listBoxX.BackColor = Color.Orange;
            }
        }

        private void Form1_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.ShiftKey)
            {
                shift_down = false;
                listBoxX.BackColor = Color.White;
            }
        }

        private void buttonTrain_Click(object sender, EventArgs e)
        {
            Z = X.Count; 
            Q = 3;
            n = 6 * 6;
            L = new double[Z, Q];

            for (int z = 0; z < Z; z++)
                for (int q = 0; q < Q; q++)
                {
                    L[z, q] = rand.NextDouble();
                }

            Train();

            MessageBox.Show("Done!");
        }

        private void listChar_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listChar.SelectedIndex<0) return;

            var v = new vec();
            v.AddRange(bitMap1.ToList());
            v.q = listChar.SelectedIndex;
            X.Add(v);

            listBoxX.DataSource = null;
            listBoxX.DataSource = X;

        }

        private void listBoxX_SelectedIndexChanged(object sender, EventArgs e)
        {
            var idx = listBoxX.SelectedIndex;
            if (idx < 0) return;

            if (!shift_down)
                bitMap1.FromList(X[idx]);
            else
            {
                X.RemoveAt(idx);
                listBoxX.DataSource = null;
                listBoxX.DataSource = X;
            } 
            
            
        }

        private void buttonSave_Click(object sender, EventArgs e)
        {
            var fw = new StreamWriter("save.txt");
            foreach (var l in X)
            {
                fw.WriteLine(l.ToString());
            }
            fw.Close();

            MessageBox.Show("Done!");
        }

        private void buttonLoad_Click(object sender, EventArgs e)
        {
            var fw = new StreamReader("save.txt");
            var lines = fw.ReadToEnd().Trim().Split('\n');
            foreach (var l in lines)
            {
                X.Add(new vec(l));
            }
            fw.Close();

            listBoxX.DataSource = null;
            listBoxX.DataSource = X;
            MessageBox.Show("Done!");
        }

        private void comboMess_SelectedIndexChanged(object sender, EventArgs e)
        {
            var idx = comboMess.SelectedIndex;
            if (idx < 0) return;

            mess = messList[idx];
        }

        private void comboK_SelectedIndexChanged(object sender, EventArgs e)
        {
            var idx = comboK.SelectedIndex;
            if (idx < 0) return;

            K = KList[idx];
        }

        private void button1_Click(object sender, EventArgs e)
        {            
            if (mess == null) return;
            if (K == null) return;
            if (X.Count <= 0) return;

            int q = GuessQ(new vec(bitMap1.ToList()),true);
            MessageBox.Show(listChar.Items[q].ToString());
            listQchar.Invalidate();

        }

        #region //CLASTER
        List<vec> cZ;
        double eps;

        void cInit()
        {
            eps = 0.0001;
            cZ = new List<vec>();
            cZ.Add(X[0]);//первый кластер

            //vec cz1 = cZ[0];

            //vec cz2 = X[0];
            //cz2.tmp = 0;

            //foreach (var x in X)
            //{
            //   var e = mEuclide(cz1, x);
            //   if (e > cz2.tmp)
            //   {
            //       cz2 = x;
            //       cz2.tmp = e;
            //   }
            //}

            //cZ.Add(cz2);
        }

        

        void Declasterise()
        {
                cInit();

                foreach (var x in X)//Все в 0 кластер
                {
                    x.tmp = mEuclide(cZ[0], x);
                    x.q = 0;
                }

                Maximin();

                listBoxX.DataSource = null;
                listBoxX.DataSource = X;
                MessageBox.Show("Done!");
        }


        void Maximin()
        {

            bool alg_ended = false;

            while (!alg_ended)
            {

                for (int xi = 0; xi < X.Count; xi++)//распределяем
                {
                    vec x = X[xi];

                    for (int ci = 0; ci < cZ.Count; ci++)
                    {
                        vec cz = cZ[ci];
                        var e = mEuclide(cz, x);

                        if (e < x.tmp)//минимум
                        {
                            x.tmp = e;
                            x.q = ci;
                        }
                    }
                }

                vec mx = X[0];
                mx.tmp = 0;
                mx.q = 0;

                for (int xi = 0; xi < X.Count; xi++)//максимин
                {
                    vec x = X[xi];
                    if (x.tmp > mx.tmp)
                    {
                        mx = x;
                    }
                }

                if (mx.tmp < AverEuclCz())
                {
                    alg_ended = true;
                }
                else
                {
                    cZ.Add(mx);
                }
            }

        }

        double AverEuclCz()
        {
            List<vec> buff = new List<vec>(cZ);
            double sum = 0;
            int num = 0;

            while (buff.Count > 1)
            {
                vec cur = buff[0];

                for (int i = 1; i < buff.Count; i++)
                {
                    sum += mEuclide(cur, buff[i]);
                    num++;
                }

                buff.Remove(cur);
            }

            return sum / num;
        }

        private void buttonToClasters_Click(object sender, EventArgs e)
        {
            Declasterise();
        }
        
        #endregion


        #region ISOMAD
        int iNc;
        int iK;
        int iOn;
        double iOp, iOc;
        double ih;
        int iL;
        int iI;

        void iInit()
        {

        }

        #endregion
    }
}
